<template>
    <div>
<router-view v-slot="{ Component }">
  <!-- 因为不同的name会执行不同的动画效果
  当我们进入一个新页面时，name变成push执行新页面跳转动画
  当我们进入一个旧页面时，name变成back执行返回动画
   -->
  <transition 
  @before-enter="beforeEnter"
  @after-leave="afterLeave"
  :name="transitionName">
  <!-- include来控制缓存组件 是一个数组，数组中的元素是组件名称 -->
    <keep-alive :include="virtualTaskStack">
  <component :is="Component" :class="{ding: isAnimate}" />
    </keep-alive>
  
  </transition>
</router-view>

    </div>
</template>

<script>
// 常量通常是大写，定义一些不变的变量
const ROUTER_TYPE_PUSH='push'
const ROUTER_TYPE_BACK='back'
const NONE='none'
const ROUTER_TYPE_ENUM=[ROUTER_TYPE_PUSH,ROUTER_TYPE_BACK, NONE]
//因为要做一个通用的组件，判断你当前的组件是否使用正确
</script>
<script setup>
import {useRouter}from 'vue-router'
import {defineProps,ref} from 'vue'
//需要做一个标记，标记你是新页面要执行的动画，要执行push动画
//需要另外的一个标记，表明返回旧页面执行back动画
let props=defineProps({
  //如果routerType push back
  //路由跳转的类型：push是进入组件，back是退出组件
 routerType:{
   type:String,
   default:NONE,
   validator(val){
    //如果我们在设置跳转的过程中没有设置push 或者back 提示开发者，你要设置
    //保证开发者一定要传递这个routerType,且routerType是push 或者back 或者none
    const result =ROUTER_TYPE_ENUM.includes(val)
    if(!result){
      // routerType的值不是pushback none 三者之一，提示错误信息
      //抛出异常
      throw new Error(`你的router_type必须是ROUTER_TYPE_ENUM其中一个`)
    }
    return result;
   }
 }
 ,//接收显示的组件,也是任务栈中第一个组件
 mainComponentName:{
  type:String,
  required:true
 }
});

let transitionName=ref("")
let router=useRouter()
router.beforeEach((to,name)=>{
  console.log(props.routerType)
  transitionName.value=props.routerType
  // 进栈出栈操作
  if(props.routerType===ROUTER_TYPE_PUSH){
    virtualTaskStack.value.push(to.name)
  }else if(props.routerType===ROUTER_TYPE_BACK){
     virtualTaskStack.value.pop()
  }
  if(to.name===props.mainComponentName){
    clerTask()
  }
    //跳回首页 清空任务栈的操作
  
})
//isAnimate控制动画执行

let isAnimate=ref(false)
const beforeEnter = () => {
  console.log("beforeEnter");
  isAnimate.value = true;
};
const afterLeave = () => {
  console.log("afterLeave");
  isAnimate.value = false;
};
//初始化一个空的任务栈,先把首页放在初始化数组中
let virtualTaskStack=ref([props.mainComponentName])
// 定义重置的任务栈方法
const clerTask=()=>{
  virtualTaskStack.value=[props.mainComponentName]
}
</script>

<style lang="scss" scoped>

.ding{
  position:fixed;
  left:0;
   top: 0;
  width: 100%;
}

// push页面时：新页面的进入动画
.push-enter-active {
  animation-name: push-in;
  animation-duration: 0.4s;
}
// push页面时：老页面的退出动画
.push-leave-active {
  animation-name: push-out;
  animation-duration: 0.4s;
}
// push页面时：新页面的进入动画
@keyframes push-in {
  0% {
    transform: translate(100%, 0);
  }
  100% {
    transform: translate(0, 0);
  }
}
// push页面时：老页面的退出动画
@keyframes push-out {
  0% {
    transform: translate(0, 0);
  }
  100% {
    transform: translate(-50%, 0);
  }
}

// 后退页面时：即将展示的页面动画
.back-enter-active {
  animation-name: back-in;
  animation-duration: 0.4s;
}
// 后退页面时：后退的页面执行的动画
.back-leave-active {
  animation-name: back-out;
  animation-duration: 0.4s;
}
// 后退页面时：即将展示的页面动画
@keyframes back-in {
  0% {
    width: 100%;
    transform: translate(-100%, 0);
  }
  100% {
    width: 100%;
    transform: translate(0, 0);
  }
}
// 后退页面时：后退的页面执行的动画
@keyframes back-out {
  0% {
    width: 100%;
    transform: translate(0, 0);
  }
  100% {
    width: 100%;
    transform: translate(50%, 0);
  }
}

</style>